import { AxiosError, type AxiosInstance, type AxiosResponse } from "axios";
import type { AxiosRequestConfig } from "axios";
import { useUserStore } from "@/stores/userStore";
import axios from "axios";
import router from "@/router";

interface XtxAxiosInstance extends AxiosInstance {
  request<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<T>;
}

export default class XtxRequestManager {
  // 用于保存单例对象的静态属性
  // 该属性不允许开发者直接访问所以将该属性设置为私有属性，开发者必须通过 instance 静态方法获取单例对象
  // 因为该属性需要被 instance 静态方法访问，所以将该属性设置为静态属性
  private static _singletonInstance: XtxRequestManager;

  // 用于保存 axios 实例对象
  private readonly _instance: XtxAxiosInstance;

  // 请求基准地址
  static baseURL: string =
    "https://pcapi-xiaotuxian-front-devtest.itheima.net/";
  // "https://apipc-xiaotuxian-front.itheima.net/";

  // 获取 user 仓库对象
  private _userStore = useUserStore();

  // 为防止开发者直接实例化 XtxRequestManager 类，将该类的构造函数设置为私有
  private constructor() {
    // 创建 axios 实例对象专门用于小兔鲜儿项目发送请求
    this._instance = axios.create({ baseURL: XtxRequestManager.baseURL });
    // 注册请求拦截器，在请求发送之前在请求头中加入 token
    // 由于注册到 use 方法中的参数方法，在内部被直接调用，所以内部的 this 指向 undefined（严格模式下）
    // 所以此处通过 bind 让方法内部的 this 指向当前类的实例
    this._instance.interceptors.request.use(
      this._addTokenToRequestHeader.bind(this)
    );
    // 注册响应拦截器
    this._instance.interceptors.response.use(
      // 剥离 axios 响应对象，直接返回到服务器的响应状态（响应拦截器 -> 成功态）
      this._peelOffAxiosResponse,
      // 登录状态时效，清空用户信息，跳转到登录页面（响应拦截器 -> 失败态）
      this._unauthorized.bind(this)
    );
  }

  // 用于获取单例对象的静态方法
  static get instance() {
    // 判断单例是否存在
    if (typeof XtxRequestManager._singletonInstance === "undefined") {
      // 单例不存在、创建单例对象
      XtxRequestManager._singletonInstance = new XtxRequestManager();
    }
    // 单例对象存在、返回单例对象
    return XtxRequestManager._singletonInstance;
  }

  // 在请求头中加入 token
  private _addTokenToRequestHeader(config: AxiosRequestConfig) {
    // 从 userStore 中获取 token
    const token = this._userStore.profile.result.token;
    // 如果 token 存在将 token  添加到请求头对象中
    if (token) config.headers = { Authorization: `Bearer ${token}` };
    // 返回配置对象 使其生效
    return config;
  }

  // 剥离 axios 响应对象，直接返回服务端的响应状态（响应拦截器 -> 成功态）
  private _peelOffAxiosResponse(response: AxiosResponse) {
    return response.data;
  }

  // 登录状态失效，清空用户信息（响应拦截器 -> 失败态）
  private _unauthorized(error: unknown) {
    if (error instanceof AxiosError) {
      if (error.response?.status === 401) {
        // 清空用户信息
        this._userStore.$reset();
        // 跳转到登录页面
        return router.push(
          `/login?return=${encodeURIComponent(
            router.currentRoute.value.fullPath
          )}`
        );
      }
      return Promise.reject(error);
    }
  }

  // 用于发送请求的方法
  public request<T = any, D = any>(config: AxiosRequestConfig): Promise<T> {
    return this._instance.request<T, D>(config);
  }
}
